1 package edu.jiangxin.apktoolbox.convert.base; 2 3 import edu.jiangxin.apktoolbox.swing.extend.EasyPanel; 4 import edu.jiangxin.apktoolbox.utils.Constants; 5 import org.apache.commons.lang3.StringUtils; 6 7 import javax.swing.*; 8 import javax.swing.event.DocumentEvent; 9 import javax.swing.event.DocumentListener; 10 import javax.swing.text.*; 11 import java.awt.*; 12 import java.awt.event.ActionEvent; 13 import java.awt.event.ActionListener; 14 import java.math.BigInteger; 15 import java.util.ArrayList; 16 import java.util.List; 17 18 public class BaseConvertPanel extends EasyPanel { 19 private static final String PROPERTY_KEY = "name"; 20 21 private static final String DECIMAL = "Decimal"; 22 23 private static final String BINARY = "Binary"; 24 25 private static final String OCTAL = "Octal"; 26 27 private static final String HEX = "Hex"; 28 29 private DocumentListener documentListener; 30 31 private DocumentFilter documentFilter; 32 33 private boolean isChangedByUser; 34 35 private final List<BaseUiObject> baseUiObjects = new ArrayList<>(); 36 37 @Override 38 public void initUI() { 39 BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS); 40 setLayout(boxLayout); 41 42 documentListener = new TextFieldDocumentListener(); 43 documentFilter = new TextFieldDocumentFilter(); 44 45 isChangedByUser = true; 46 47 baseUiObjects.add(new BaseUiObject(2)); 48 baseUiObjects.add(new BaseUiObject(8)); 49 baseUiObjects.add(new BaseUiObject(10)); 50 baseUiObjects.add(new BaseUiObject(16)); 51 52 for (BaseUiObject baseUiObject : baseUiObjects) { 53 add(baseUiObject.panel); 54 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER)); 55 } 56 57 JButton clearBtn = new JButton("Clear"); 58 clearBtn.addActionListener(new ClearButtonActionListener()); 59 add(clearBtn); 60 } 61 62 63 class ClearButtonActionListener implements ActionListener { 64 @Override 65 public void actionPerformed(ActionEvent arg0) { 66 isChangedByUser = false; 67 for (BaseUiObject baseUiObject : baseUiObjects) { 68 baseUiObject.textField.setText(""); 69 } 70 isChangedByUser = true; 71 } 72 } 73 74 class TextFieldDocumentListener implements DocumentListener { 75 @Override 76 public void changedUpdate(DocumentEvent e) { 77 } 78 79 @Override 80 public void insertUpdate(DocumentEvent e) { 81 detect(e); 82 } 83 84 @Override 85 public void removeUpdate(DocumentEvent e) { 86 detect(e); 87 } 88 } 89 90 class TextFieldDocumentFilter extends DocumentFilter { 91 @Override 92 public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException { 93 Document doc = fb.getDocument(); 94 StringBuilder sb = new StringBuilder(); 95 sb.append(doc.getText(0, doc.getLength())); 96 sb.insert(offset, string); 97 98 Object propertyObj = doc.getProperty(PROPERTY_KEY); 99 if (propertyObj == null) { 100 Toolkit.getDefaultToolkit().beep(); 101 return; 102 } 103 Integer radix = (Integer) doc.getProperty(PROPERTY_KEY); 104 if (isValidText(radix, sb.toString())) { 105 super.insertString(fb, offset, string, attr); 106 } else { 107 Toolkit.getDefaultToolkit().beep(); 108 } 109 } 110 111 @Override 112 public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { 113 Document doc = fb.getDocument(); 114 StringBuilder sb = new StringBuilder(); 115 sb.append(doc.getText(0, doc.getLength())); 116 sb.replace(offset, offset + length, text); 117 118 Object propertyObj = doc.getProperty(PROPERTY_KEY); 119 if (propertyObj == null) { 120 Toolkit.getDefaultToolkit().beep(); 121 return; 122 } 123 Integer radix = (Integer) doc.getProperty(PROPERTY_KEY); 124 if (isValidText(radix, sb.toString())) { 125 super.replace(fb, offset, length, text, attrs); 126 } else { 127 Toolkit.getDefaultToolkit().beep(); 128 } 129 } 130 } 131 132 private void detect(DocumentEvent documentEvent) { 133 Document doc = documentEvent.getDocument(); 134 Integer radix = (Integer) doc.getProperty(PROPERTY_KEY); 135 convertMe(radix); 136 } 137 138 private void convertMe(int radix) { 139 if (!isChangedByUser) { 140 return; 141 } 142 143 BigInteger value = null; 144 for (BaseUiObject baseUiObject : baseUiObjects) { 145 if (baseUiObject.radix == radix) { 146 String text = baseUiObject.textField.getText(); 147 if (StringUtils.isEmpty(text)) { 148 value = null; 149 } else { 150 value = new BigInteger(text, radix); 151 } 152 } 153 } 154 isChangedByUser = false; 155 for (BaseUiObject baseUiObject : baseUiObjects) { 156 if (baseUiObject.radix != radix) { 157 if (value == null) { 158 baseUiObject.textField.setText(""); 159 } else { 160 baseUiObject.textField.setText(value.toString(baseUiObject.radix)); 161 } 162 } 163 } 164 isChangedByUser = true; 165 } 166 167 private boolean isBinStr(String str) { 168 if (str == null) { 169 return false; 170 } 171 for (int i = 0; i < str.length(); i++) { 172 if ((str.charAt(i) != '1') && (str.charAt(i) != '0')) { 173 return false; 174 } 175 } 176 return true; 177 } 178 179 private boolean isDecStr(String str) { 180 if (str == null) { 181 return false; 182 } 183 for (int i = 0; i < str.length(); i++) { 184 if ((str.charAt(i) < '0') || (str.charAt(i) > '9')) { 185 return false; 186 } 187 } 188 return true; 189 } 190 191 private boolean isOctStr(String str) { 192 if (str == null) { 193 return false; 194 } 195 for (int i = 0; i < str.length(); i++) { 196 if ((str.charAt(i) < '0') || (str.charAt(i) > '7')) { 197 return false; 198 } 199 } 200 return true; 201 } 202 203 private boolean isHexStr(String str) { 204 if (str == null) { 205 return false; 206 } 207 for (int i = 0; i < str.length(); i++) { 208 char c = str.charAt(i); 209 if ((c < '0' || c > '9') && (c < 'A' || c > 'F') && (c < 'a' || c > 'f')) { 210 return false; 211 } 212 } 213 return true; 214 } 215 216 private boolean isValidText(int radix, String text) { 217 switch (radix) { 218 case 2 -> { 219 return isBinStr(text); 220 } 221 case 8 -> { 222 return isOctStr(text); 223 } 224 case 10 -> { 225 return isDecStr(text); 226 } 227 case 16 -> { 228 return isHexStr(text); 229 } 230 default -> { 231 return false; 232 } 233 } 234 } 235 236 class BaseUiObject { 237 int radix; 238 239 JPanel panel; 240 241 JLabel label; 242 243 JTextField textField; 244 245 BaseUiObject(int radix) { 246 this.radix = radix; 247 panel = new JPanel(); 248 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); 249 250 label = new JLabel(this + ":"); 251 label.setPreferredSize(new Dimension(50, 25)); 252 253 textField = new JTextField(); 254 textField.getDocument().addDocumentListener(documentListener); 255 ((PlainDocument) textField.getDocument()).setDocumentFilter(documentFilter); 256 textField.getDocument().putProperty(PROPERTY_KEY, radix); 257 258 panel.add(label); 259 panel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER)); 260 panel.add(textField); 261 } 262 263 @Override 264 public String toString() { 265 switch (radix) { 266 case 2 -> { 267 return BINARY; 268 } 269 case 8 -> { 270 return OCTAL; 271 } 272 case 10 -> { 273 return DECIMAL; 274 } 275 case 16 -> { 276 return HEX; 277 } 278 default -> { 279 return String.valueOf(radix); 280 } 281 } 282 } 283 } 284 }